using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using GameLib.GameItem;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Common.PolygonManipulation;


namespace GameLib.GameScreen
{
    class GamePlayScreen : GameScreen
    {
        ItemManager itemManager;
        Texture2D background;

        int lineThichness = 6;
        Texture2D tempCanvas;
        Color[] tempPixels;
        List<float> xCollection = new List<float>();
        List<Layer> layers = new List<Layer>();

        World world;
        Body lineBody;
        Body ballBody;
        Texture2D ballTexture;
        List<Body> bodyList;
        Boolean isStart = false;

        public GamePlayScreen(ScreenManager manager)
            : base(manager)
        {
            Load();
        }

        public override void Load()
        {
            world = new World(new Vector2(0, 2f));

            TouchPanel.EnabledGestures = GestureType.FreeDrag | GestureType.DragComplete;
            background = content.Load<Texture2D>(@"Images\background");
            itemManager = new ItemManager();

            GameButton btn_Play = new GameButton(content.Load<Texture2D>(@"Images\play"), new Vector2(620, 380), null, null, itemManager);
            btn_Play.ItemPress += new EventHandler(btn_Play_Press);
            itemManager.AddItem(btn_Play);

            GameButton btn_Undo = new GameButton(content.Load<Texture2D>(@"Images\undo"), new Vector2(700, 384), null, null, itemManager);
            btn_Undo.ItemPress += new EventHandler(btn_Undo_Press);
            itemManager.AddItem(btn_Undo);

            GameButton btn_Clean = new GameButton(content.Load<Texture2D>(@"Images\clean"), new Vector2(750, 384), null, null, itemManager);
            btn_Clean.ItemPress += new EventHandler(btn_Clean_Press);
            itemManager.AddItem(btn_Clean);

            ///////////////////////////////////////////////
            ballTexture = content.Load<Texture2D>(@"Images\ball_1");

            //Vector2 screenCenter = new Vector2(manager.Graphics.Viewport.Width / 2f,
            //                                   manager.Graphics.Viewport.Height / 2f);
            //Vector2 circlePosition = ConvertUnits.ToSimUnits(screenCenter) + new Vector2(0, -1.5f);
            //Vector2 groundPosition = ConvertUnits.ToSimUnits(screenCenter) + new Vector2(0, 1.25f);

            Rectangle bounds=manager.Game.GraphicsDevice.Viewport.Bounds;
            ballBody = BodyFactory.CreateCircle(world, ConvertUnits.ToSimUnits(ballTexture.Width/2f), 1f, 
                ConvertUnits.ToSimUnits(new Vector2(bounds.Width/2,ballTexture.Height/2)));
            ballBody.BodyType = BodyType.Dynamic;
            ballBody.Restitution = 0.3f;
            ballBody.Friction = 0.5f;

            bodyList = new List<Body>();
            ////////////////////////////////////////////////
            Rectangle viewportBounds = manager.Graphics.Viewport.Bounds;
            tempCanvas = new Texture2D(manager.Graphics, viewportBounds.Width, viewportBounds.Height);
            tempPixels = new Color[tempCanvas.Width * tempCanvas.Height];
            for (int i = 0; i < tempPixels.Length; i++)
            {
                tempPixels[i] = Color.Transparent;
            }
            tempCanvas.SetData<Color>(tempPixels);
            /////////////////////////////////////////////////

            this.LoadComplete = true;
        }

        public override void UnLoad()
        {
            base.UnLoad();
        }

        public override void Update(GameTime gametime)
        {
            TouchCollection touchCollection = TouchPanel.GetState();

            GamePadState state = GamePad.GetState(PlayerIndex.One);
            if (state.Buttons.Back == ButtonState.Pressed)
            {
                manager.RemoveAndAdd(this, ScreenName.GameTitle);
            }

            bool canvasNeedsUpdate = false;
            int yMinUpdate = Int32.MaxValue, yMaxUpdate = 0;

            foreach (TouchLocation touch in touchCollection)
            {
                if (touch.State == TouchLocationState.Pressed)
                {
                    itemManager.CheckPress(touch.Position);
                }
            }

            while (TouchPanel.IsGestureAvailable)
            {
                GestureSample gesture = TouchPanel.ReadGesture();
                if (gesture.GestureType == GestureType.FreeDrag)
                {
                    Vector2 point1 = gesture.Position - gesture.Delta;
                    Vector2 point2 = gesture.Position;

                    RoundCappedLine line = new RoundCappedLine(point1, point2, lineThichness);
                    int yMin = (int)(Math.Min(point1.Y, point2.Y) - lineThichness - 1);
                    int yMax = (int)(Math.Max(point1.Y, point2.Y) + lineThichness + 1);
                    yMin = Math.Max(0, Math.Min(tempCanvas.Height, yMin));
                    yMax = Math.Max(0, Math.Min(tempCanvas.Height, yMax));
                    for (int y = yMin; y < yMax; y++)
                    {
                        xCollection.Clear();
                        line.GetAllX(y, xCollection);
                        if (xCollection.Count == 2)
                        {
                            int xMin = (int)(Math.Min(xCollection[0],
                                                      xCollection[1]) + 0.5f);
                            int xMax = (int)(Math.Max(xCollection[0],
                                                      xCollection[1]) + 0.5f);
                            xMin = Math.Max(0, Math.Min(tempCanvas.Width, xMin));
                            xMax = Math.Max(0, Math.Min(tempCanvas.Width, xMax));
                            for (int x = xMin; x < xMax; x++)
                            {
                                tempPixels[y * tempCanvas.Width + x] = Color.Red;
                            }
                            yMinUpdate = Math.Min(yMinUpdate, yMin);
                            yMaxUpdate = Math.Max(yMaxUpdate, yMax);
                            canvasNeedsUpdate = true;
                        }
                    }
                }
                else
                {
                    Layer newLayer = new Layer(manager.Graphics, tempPixels);
                    for (int i = 0; i < tempPixels.Length; i++)
                    {
                        tempPixels[i] = Color.Transparent;
                    }
                    layers.Add(newLayer);
                    manager.Graphics.Textures[0] = null;
                    tempCanvas.SetData<Color>(tempPixels);
                }
            }

            ////////////////////////////////////////////////////////////////////////
            if (canvasNeedsUpdate)
            {
                manager.Graphics.Textures[0] = null;
                int height = yMaxUpdate - yMinUpdate;
                Rectangle rect = new Rectangle(0, yMinUpdate, tempCanvas.Width, height);
                tempCanvas.SetData<Color>(0, rect, tempPixels,
                            yMinUpdate * tempCanvas.Width, height * tempCanvas.Width);
            }
            ////////////////////////////////////////////////////////////////////////

            if (isStart)
            {
                world.Step(Math.Min((float)gametime.ElapsedGameTime.TotalSeconds, (1f / 30f)));
            }

            itemManager.Update(gametime);
            base.Update(gametime);
        }

        public override void Draw(SpriteBatch spritebatch)
        {
            spritebatch.Draw(background, Vector2.Zero, Color.White);
            itemManager.Draw(spritebatch);
            spritebatch.Draw(tempCanvas, Vector2.Zero, Color.White);

            spritebatch.Draw(ballTexture, ConvertUnits.ToDisplayUnits(ballBody.Position), null, 
                Color.White, 0f, new Vector2(ballTexture.Width / 2, ballTexture.Height / 2), 1f, SpriteEffects.None, 0f);
            foreach (Layer l in layers)
            {
                l.Draw(spritebatch);
            }
            base.Draw(spritebatch);
        }

        //new Version of MergeAllLayer
        private void MergeAllLayer()
        {
            foreach (Layer l in layers)
            {
                uint[] data = new uint[l.Pixels.Length];
                l.Canvas.GetData(data);
                Vertices textureVertices = PolygonTools.CreatePolygon(data, l.Canvas.Width, false);
                List<Vertices> list = BayazitDecomposer.ConvexPartition(textureVertices);
                Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(1)) * 1f;
                Vector2 position = new Vector2(float.MaxValue, float.MaxValue);
                foreach (Vertices vertices in list)
                {
                    vertices.Scale(ref vertScale);
                    foreach (Vector2 point in vertices)
                    {
                        position.X = Math.Min(position.X, point.X);
                        position.Y = Math.Min(position.Y, point.Y);
                    }
                }

                Body tempBody = BodyFactory.CreateCompoundPolygon(world, list, 1f, BodyType.Dynamic);
                tempBody.Position = ConvertUnits.ToSimUnits(position);
                tempBody.Restitution = 0.3f;
                tempBody.Friction = 0.5f;

                bodyList.Add(tempBody);
            }
        }

        //private void MergeAllLayer()
        //{
        //    Layer tempLayer = new Layer(manager.Graphics);
        //    int numberRed = 0;

        //    for (int i = 0; i < tempLayer.Pixels.Length; i++)
        //    {
        //        tempLayer.Pixels[i] = Color.Transparent;
        //        foreach (Layer l in layers)
        //        {
        //            if (l.Pixels[i] == Color.Red)
        //            {
        //                tempLayer.Pixels[i] = Color.Red;
        //                numberRed++;
        //                break;
        //            }
        //        }
        //    }
        //    if (numberRed == 0)
        //    {
        //        return;
        //    }
        //    tempLayer.SetData();

        //    layers.Clear();
        //    layers.Add(tempLayer);

        //    uint[] data = new uint[tempLayer.Pixels.Length];
        //    tempLayer.Canvas.GetData(data);
        //    Vertices textureVertices = PolygonTools.CreatePolygon(data, tempLayer.Canvas.Width, false);
        //    List<Vertices> list = BayazitDecomposer.ConvexPartition(textureVertices);
        //    Vector2 vertScale = new Vector2(ConvertUnits.ToSimUnits(1)) * 1f;
        //    Vector2 position = new Vector2(float.MaxValue, float.MaxValue);
        //    foreach (Vertices vertices in list)
        //    {
        //        vertices.Scale(ref vertScale);
        //        foreach (Vector2 point in vertices)
        //        {
        //            position.X = Math.Min(position.X, point.X);
        //            position.Y = Math.Min(position.Y, point.Y);
        //        }
        //    }

        //    lineBody = BodyFactory.CreateCompoundPolygon(world, list, 1f, BodyType.Dynamic);
        //    lineBody.Position = ConvertUnits.ToSimUnits(position);
        //    lineBody.Restitution = 0.3f;
        //    lineBody.Friction = 0.5f;
        //}

        private void Undo()
        {
            if (layers.Count > 0)
            {
                layers.RemoveAt(layers.Count - 1);
            }
        }

        private void Clean()
        {
            layers.Clear();
        }

        private void btn_Play_Press(object sender, EventArgs e)
        {
            MergeAllLayer();
            isStart = true;
        }

        private void btn_Undo_Press(object sender, EventArgs e)
        {
            Undo();
        }

        private void btn_Clean_Press(object sender, EventArgs e)
        {
            Clean();
        }
    }
}

